/**
 * stm.h
 * @brief contiene le funzioni principali per realizzare la logica STM dell'algoritmo
 *
 * la libreria comunica sia con il livello ltm (da cui riceve una soluzione costruttiva) che con
 * il LOS.
 * La libreria puo' essere richiamata tramite il suo metodo principale, la funzione executeSTM().
 *
 *  Created on: May 6, 2013
 *      Author: patrizio
 */

#ifndef STM_H_
#define STM_H_

#include <stdbool.h>
#include "solution.h"
#include "graph.h"
#include "tabooState.h"
#include "los.h"
#include "vectorParam.h"
#include "ALGConfiguration.h"

/**indica il numero di mosse che STM dispone per pilotare il LOS. Al momento sono 3 ossia:
 * \li ADD
 * \li SWAP
 * \li REMOVE
 *
 */
#define STM_MOVES_AVAILABLE 3

//TODO rimuovere pictures!!!
#define STM_PICTURE_PATTERNNAME "../pictures/solution%04lu.bmp"
/** Script matlab per disegnare le K serie storiche delle funzioni obiettivo durante l'esecuzione di un STM */
#define STM_MATLAB_F_OBJ_HISTORY "../matlab-interface/fObjHistory.m"
/** Script matlab per disegnare lo storico e l'istogramma delle decisioni durante l'esecuzione di un STM */
#define STM_MATLAB_MOVES_HISTORY "../matlab-interface/movesHistory.m"
/**indica il file in cui stm va a scrivere ogni sua mossa cosa comporta */
#define STM_LOGFILE "../pictures/stm.log"

/** Struttura contenente tutte e sole le configurazioni di cui STM necessita per girare. Comprende dunque la configurazione di LOS. */
typedef struct STMConfiguration {

	/**se impostato a TRUE l'algoritmo disegna ogni singola iterazione STM ottenuta. <b>Attenzione</b> questa azione
	 * rallenta enormemente l'algoritmo!*/
	bool drawSolutionBMP;
	/**se impostato a TRUE l'algoritmo genera dei file .m che possono essere analizzati con strumenti come
	 * MATLAB o Octave. In questo modo poi lo storico STM puo' essere facilmente plottato.*/
	bool drawSolutionOctave;
	/**indica il numero massimo di iterazioni che possono essere effettuate in un unica risoluzione STM*/
	int maximumLOSIterationNumber;
	/**indica il numero massimo di iterazioni accettate con peggioramento di soluzione in STM prima di terminare
	 * STM stessa*/
	int maximumLOSWorseningIterationNumber;

	pLOSConfiguration pLOSconfig;
} STMConfiguration;

typedef STMConfiguration* pSTMConfiguration;

//TODO documentazione
pSTMConfiguration initSTMConfiguration(PalgConfiguration pALGconfig);

//TODO PAT serve anche un freeSTMCOnfiguration per evitare il memoryleak dell'applicazione!

//TODO ragionare su questa taboolist... non sono sicuro che serva davvero!
//TODO forse sarebbe bello creare una struttura che gestisca appostiamente tale struttura... pero' e' soltanto una sottigliezza
/**indica la tabooList delle mosse. Ipotizziamo infatti che abbiamo fatto 100 swap e siamo ancora a capacita' rimanenti (T/2;Q/2). Forse
 * e' meglio abolire la swap per un po' di tempo e lasciare che add e remove facciano il loro corso!
 *
 */
TabooExpire moveTabooList[STM_MOVES_AVAILABLE];

/**indica la matrice di covarianza da utilizzare per correlare la variabile tau e theta all'interno delle gaussiane contenute
 * nel valutatore.
 * \li l'indice 0 si riferisce ai tempi
 * \li l'indice 1 si riferisce alle cpaacita'
 */
float stmCovariance[2][2];

/**indica il determinante di stmCovariance , definito come
 * \f[
 *|Cov|=Cov_{11} Cov_{00} - Cov_{01} a_{10}
 * \f]
 *
 */
float stmCovarianceDet;

/**rappresenta l'inversa della matrice di covarianza. Assicurarsi che il determinante sia diverso da 0
 *
 */
float stmCovarianceInv[2][2];

/**indica un coefficiente che amplifica il valore della gaussiana. Esso si configura di fatto come il massimo raggiungibile
 * da un singolo valutatore di una mossa
 *
 */
float stmGaussianAmplifier;

/**indica il logaritmo della base della gaussiana, ossia:
 * \f[
 * log(a)
 * \f]
 * questo valore modifica la varianza della gaussiana per rendere i numeri ritornati dal valutatore non troppo piccoli
 */
float stmGaussianLogBase;

/**indica un coefficiente che si configura com il minimo valore ottenibile da un valutatore di una mossa. In questo modo
 * e' possibile limitare gli errori di approssimazione provocati dalla granularita' del tipo float
 */
float stmMinProbabilisticValue;

/**computa il valore che si configura come l'esponente di un'esponenziale in una gaussiana, ossia:
 * \f[
 *	{-\frac{1}{2}}{log(a)}(v^{T}\;Cov^{-1}\;v)
 * \f]
 *
 * \pre
 *	\li la funzione initSTMEngine() deve essere gia' stata richiamata
 *	\li v non NULL
 *
 * @param v indica il vettore 2x1 contenente il valore tau al primo indice e theta al secondo indice del camion considerato
 * @return un numero che puo' essere posrto come esponente di un esponenziale per implementare una gaussiana
 */
float computeExponent(PvectorParam v);

/**computa il valore di una campana di gauss, ossia:
 * \f[
 * 	A e^{-\frac{1}{2}}{log(a)}(v^{T}\;Cov^{-1}\;v)
 * \f]
 * dove:
 * \li A e' stmGaussianAmplifier;
 * \li log(a) e' un valore calcolato in modo che la guassiana sia sempre maggiore di stmMinProbabilisticValue;
 * \li Cov e' stmCovariance.
 *
 * \pre
 *  \li la funzione initSTMEngine() deve essere gia' stata richiamata
 *  \li x non NULL
 * \post
 *  un valore float compreso tra stmMinProbabilisticValue e stmGaussianAmplifier
 *
 * @param x il vettore 2x1 che abbia come prima coordinata tau e come seconda coordinata theta
 * @return un valutatore
 */
float computeGaussian(PvectorParam x);

/**inizializza i parametri essenziali per far funzionare correttamente STM. Tale funzione deve essere richiamata prima di qualunque altra funzione
 * di STM
 *
 * \pre
 *  \li almeno uno dei parametri T e Q deve essere diverso da 0
 * \post
 *  \li la matrice di covarianza e' impostata
 *	\li il determinante della matrice di covaraizan e' imposta
 *	\li la matrice inversa della matrice di covarianza e' impostata
 *	\li la base dell'esponenziale nel calcolo delle gaussiane e' impostato
 *	\li srand e' stato richiamato una e una sola volta a prescindere dal numero di chiamate di questa funzione
 *
 * @param T il tempo massimo dato ai camion per percorrere un qualunque cammino
 * @param Q la capacita' massima supportata dai camion
 * @param generateFobjHistory vero sse si vuole scrivere su file uno script matlab/octave per plots dello storico per la funzione obiettivo
 * @param generateMovesHistory vero sse si vuole scrivere su file uno script matlab/octave per lo scatterplot e l'istogramma delle mosse scelte.
 */
void initSTMEngine(int T, int Q);

/**esegue il sottolivello STM.
 * Per conoscere come funziona il livello STM concettualmente visitare l'URL http://code.google.com/p/opt-alg/wiki/ShortTermMemory .
 *
 * \pre
 *	\li p_solution non NULL
 *	\li p_graph non NULL
 *	\li initSTMEngine e' gia' stato richiamato precedentemente e con successo almeno una volta
 *	\li p_taboostate non NULL
 * \post
 *	\li p_solution viene sovracritta in modo che al suo interno sia contenuta la soluzione che secondo STM e' la migliore possibile
 *	\li p_taboostate viene modificata in modo che contenga i valori di taboo dell'ultima iterazione LOS
 *	\li in totalIteration viene inserito il numero di iterazioni globali LOS
 *	\li in solutionintensity viene inserito da quante iterazioni la soluzione riulasciata da STM era considerata ottima
 *	\li i puntatori p_solution e il valore di ritorno di executeSTM() puntano alla stessa soluzione
 *
 * @param initsolution la soluzione iniziale con cui iniziare l'algoritmo
 * @param graph il grafo su cui elaborare l'ottimo
 * @param ptaboostate la taboo state gia' inizializzata dal LTM
 * @param totalIteration una cella di memoria in cui immagazzinare il numero di iterazioni LOS eseguite in STM. Se il valore non interessa inserire il valore NULL
 * @param solutionintensity una cella di memoria in cui immagazzinare da quante iterazioni LOS la soluzione contenuta in p_solution era considerata la migliore. Se il valore non interessa inserire il valore NULL
 * @param pSTMconfig il sottoinsieme delle config relativo a STM e ai suoi livelli inferiori.
 * @return la soluzione migliore fino ad ora trovata
 */
Psolution executeSTM(Psolution p_solution, Pgraph p_graph, PtabooState p_taboostate,int* totalIteration, int* solutionintensity,pSTMConfiguration pSTMconfig);

/**indica se l'algoritmo STM deve terminare il suo continuo ciclo. Questa funzione e' vera qualora:
 * \li si sia superato un numero di iterazioni massime globale dell'algoritmo
 * \li non si abbia avuto un incremento della funzione obiettivo dal un certo numero di iterazioni
 *
 *
 * @param iterationNumber indica il numero di iterazioni corrente
 * @param maxIterationNumber indica il numero massimo di iterazioni globale dell'algoritmo STM
 * @param lastIncrementingIteration indica il numero corrente di iterazioni dall'ultimo incremento della funzione obiettivo
 * @param maxContigousDecrementingIteration indica il numero massimo di iterazioni dall'ultimo incremento della funzione obiettivo entro le quali STM si ferma
 * @return TRUE se l'algoritmo deve fermarsi, FALSE altrimenti
 */
bool stmMustContinue(TabooExpire iterationNumber, TabooExpire maxIterationNumber, TabooExpire lastIncrementingIteration, TabooExpire maxContigousDecrementingIteration);

/**ricava la prossima mossa che il LOS dovra' eseguire.
 *
 * \pre
 *  \li x non NULL
 *  \li i quattro parametro contengono in prima posizione il tempo e in seconda posizione la capacita'
 *  \li averageAdd, averageSwap e averageRemove non NULL
 * \post
 *  \li uno dei valori tra MOVE_ADD, MOVE_SWAP e MOVE_REMOVE
 *
 * @param x il vettore contenente i valori tempo e capacita' residui del camion
 * @param averageAdd il punto in cui la probabilita' di fare Add e' massima
 * @param averageSwap il punto in cui la probabilita' di fare Swap e' massima
 * @param averageRemove il punto in cui la probabilita' di fare Remove e' massima
 * @return uno dei valori tra MOVE_ADD, MOVE_SWAP o MOVE_REMOVE
 */
int selectBestLOSMove(PvectorParam x, PvectorParam averageAdd, PvectorParam averageSwap, PvectorParam averageRemove);

/** TODO doc. snellimento codice executeSTM */
void initializeOutputScripts(FILE** pfObjHistory, FILE** pmovesHistory, int K, int T, int Q, Psolution ps);
/** TODO doc. snellimento codice executeSTM */
void updateOutputScripts(FILE* fObjHistory, FILE* movesHistory, int k, int T, int Q, int moveToApply, int LOSExitStatus, PvehicleState pvs, TabooExpire currentIteration);
/** TODO doc. snellimento codice executeSTM */
void finalizeOutputScripts(FILE* fObjHistory, FILE* movesHistory, int K, TabooExpire finalIteration);

#endif
